/**
 * Copyright 2009-2019 the original author or authors.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.ibatis.reflection.property;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.reflection.Reflector;

/**
 * @author Clinton Begin
 * 属性拷贝器
 */
public final class PropertyCopier {

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        a.setName("ydj");
        a.setAge(24);
        List<B> list = new ArrayList<>();
        list.add(new B("code1"));
        list.add(new B("code2"));
        list.add(new B("code3"));
        a.setList(list);

        copyBeanProperties(A.class, a, b);


        System.out.println(b.getName());

    }


    private PropertyCopier() {
        // Prevent Instantiation of Static Class
    }

    /**
     * 完成对象的输出拷贝
     *
     * @param type            对象的类型
     * @param sourceBean      提供属性值的对象
     * @param destinationBean 要被写入新属性值的对象
     */
    public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) {
        // 这两个对象同属的类
        Class<?> parent = type;
        while (parent != null) {
            // 获取该类的所有属性
            // 注意：getDeclaredFields方法返回的属性中不包含继承属性
            final Field[] fields = parent.getDeclaredFields();
            // 循环遍历属性进行拷贝
            for (Field field : fields) {
                try {
                    try {
                        field.set(destinationBean, field.get(sourceBean));
                    } catch (IllegalAccessException e) {
                        if (Reflector.canControlMemberAccessible()) {
                            field.setAccessible(true);
                            field.set(destinationBean, field.get(sourceBean));
                        } else {
                            throw e;
                        }
                    }
                } catch (Exception e) {
                    // Nothing useful to do, will only fail on final fields, which will be ignored.
                }
            }
            parent = parent.getSuperclass();
        }
    }

    static class A {
        String name;
        int age;
        List<B> list;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public List<B> getList() {
            return list;
        }

        public void setList(List<B> list) {
            this.list = list;
        }
    }

    static class B extends A {
        String code;

        public B() {
        }

        public B(String code) {
            this.code = code;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }
    }

}
